package com.canyou.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.canyou.constants.CommonConstants;
import com.canyou.datascope.DataScope;
import com.canyou.common.DataImportVO;
import com.canyou.enums.DataPermEnum;
import com.canyou.enums.ErrorCodeEnum;
import com.canyou.enums.SexEnum;
import com.canyou.exception.CysBusinessException;
import com.canyou.operlog.OpLogUtils;
import com.canyou.system.entity.user.UserDTO;
import com.canyou.system.entity.user.UserDetailVO;
import com.canyou.system.entity.user.UserListVO;
import com.canyou.system.mapper.*;
import com.canyou.system.model.*;
import com.canyou.system.service.*;
import com.canyou.utils.DateUtils;
import com.canyou.utils.Oauth2Utils;
import com.canyou.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 用户服务实现类
 *
 * @author canyou
 * @since 2019-05-14
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private OrganizationService organizationService;

    @Autowired
    private DeptService deptService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private UserRoleService userRoleService;

    @Override
    public User getByUserName(String userName) {
        return getOne(new QueryWrapper<User>().lambda().eq(User::getUsername, userName));
    }

    @Override
    public IPage<UserListVO> getPageList(IPage<UserListVO> page, String username, String realName) {
        DataScope dataScope = new DataScope().setDataPermEnum(DataPermEnum.ORG_AND_CHILDREN);
        return baseMapper.getPageList(page, dataScope, username, realName);
    }

    @Override
    public List<UserListVO> getList(String username, String realName) {
        return baseMapper.getPageList(new DataScope().setDataPermEnum(DataPermEnum.ORG_AND_CHILDREN), username, realName);
    }

    @Override
    public UserDetailVO getUserDetailById(Long userId) {
        return baseMapper.getUserDetailById(userId);
    }

    @Override
    public List<Long> getRoleIdListByUserId(Long userId) {
        return userRoleService.list(Wrappers.<UserRole>lambdaQuery().eq(UserRole::getUserId, userId))
                .stream()
                .map(UserRole::getRoleId)
                .collect(Collectors.toList());
    }

    @Override
    public boolean deleteUserRoleByUserId(Long userId) {
        return userRoleService.remove(Wrappers.<UserRole>lambdaQuery().eq(UserRole::getUserId, userId));
    }

    @Override
    public boolean saveOrUpdateUser(UserDTO userDTO) {
        User user = new User();
        if (userDTO.getId() != null) {
            user = getById(userDTO.getId());
            if (user == null) {
                throw new CysBusinessException(ErrorCodeEnum.ILLEGAL, StringUtils.format("userId: {} 对应的用户不存在", userDTO.getId()));
            }
            OpLogUtils.logDataId(StringUtils.format("用户【{}】", user.getUsername()));
            OpLogUtils.logEdit(user, userDTO, "email", "mobile", "birthday", "sex", "realName");
        }
        BeanUtils.copyProperties(userDTO, user);
        if (userDTO.getId() == null) {
            user.setPassword(applicationContext.getBean(PasswordEncoder.class).encode(CommonConstants.DEFAULT_PASSWORD));
        }
        // 删除原用户角色
        boolean res = deleteUserRoleByUserId(userDTO.getId());
        // 保存用户信息
        res = res && saveOrUpdate(user);
        final Long userId = user.getId();
        // 保存用户角色信息
        res = res && userRoleService.saveBatch(userDTO.getRoleId()
                .stream()
                .map(roleId -> new UserRole()
                        .setUserId(userId)
                        .setRoleId(roleId))
                .collect(Collectors.toList()));
        if (!res) {
            throw new CysBusinessException(ErrorCodeEnum.ILLEGAL, "保存用户信息失败");
        }
        return true;
    }

    @Override
    public List<String> getMenuListByUserName(String username) {
        return baseMapper.getMenuListByUserName(username);
    }

    private long getUserCountByOrgIdOrDeptId(Long orgId, Long deptId) {
        LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.lambdaQuery();
        if (orgId != null) {
            lambdaQueryWrapper.eq(User::getOrgId, orgId);
        }
        if (deptId != null) {
            lambdaQueryWrapper.eq(User::getDeptId, deptId);
        }
        return baseMapper.selectCount(lambdaQueryWrapper);
    }

    @Override
    public long getUserCountByOrgId(Long orgId) {
        return getUserCountByOrgIdOrDeptId(orgId, null);
    }

    @Override
    public long getUserCountByDeptId(Long deptId) {
        return getUserCountByOrgIdOrDeptId(null, deptId);
    }

    @Override
    public boolean removeUserById(Long userId) {
        // 删除原用户角色
        boolean res = deleteUserRoleByUserId(userId);
        // 删除用户
        res = res && removeById(userId);
        if (!res) {
            throw new CysBusinessException(ErrorCodeEnum.ILLEGAL, "删除用户信息失败");
        }
        return true;
    }

    @Override
    public DataImportVO importData(List<Map<String, Object>> userList) {
        DataImportVO importMessageVO = new DataImportVO();
        int successCount = 0;
        List<Integer> failList = new ArrayList<>();
        List<Integer> illegalList = new ArrayList<>();

        final PasswordEncoder passwordEncoder = applicationContext.getBean(PasswordEncoder.class);
        for (int i = 0; i < userList.size(); i++) {
            Map<String, Object> user = userList.get(i);
            if (!validImportData(user)) {
                illegalList.add((i + 1));
                continue;
            }
            // 机构数据处理
            List<Organization> orgList = organizationService.list(new QueryWrapper<Organization>()
                    .lambda().eq(Organization::getOrgName, user.get("orgName").toString()));
            if (orgList.size() > 0) {
                user.put("orgId", orgList.get(0).getId());
            } else {
                illegalList.add((i + 1));
                continue;
            }
            // 部门数据处理
            List<Dept> deptList = deptService.list(new QueryWrapper<Dept>()
                    .lambda().eq(Dept::getDeptName, user.get("deptName").toString()));
            if (deptList.size() > 0) {
                user.put("deptId", deptList.get(0).getId());
            } else {
                illegalList.add((i + 1));
                continue;
            }
            // 角色数据处理
            String[] roleName = user.get("roleName").toString().split(",");
            String roleId = Arrays.stream(roleName)
                    .flatMap(name -> roleService.list(new QueryWrapper<Role>()
                            .lambda()
                            .eq(Role::getRoleName, name))
                            .stream())
                    .map(role -> role.getId().toString())
                    .collect(Collectors.joining(","));
            if (StrUtil.isNotBlank(roleId)) {
                user.put("roleId", roleId);
            } else {
                illegalList.add((i + 1));
                continue;
            }
            // 性别数据处理
            Integer sex;
            if (user.get("sex") != null) {
                sex = SexEnum.codeOf(user.get("sex").toString());
                user.put("sex", sex);
            }
            // 日期数据处理
            LocalDateTime birthday = DateUtils.date2LocalDateTime(StringUtils.tranferDate(user.get("birthday")));
            user.put("birthday", birthday);

            User userBean = BeanUtil.mapToBean(user, User.class, true);
            // 用户重名判断
            if (existUser(userBean.getUsername(), userBean.getId())) {
                userBean.setPassword(passwordEncoder.encode(CommonConstants.DEFAULT_PASSWORD));
                UserDTO userDTO = new UserDTO();
                BeanUtils.copyProperties(userBean, userDTO);
                if (saveOrUpdateUser(userDTO)) {
                    successCount++;
                } else {
                    failList.add((i + 1));
                }
            } else {
                illegalList.add((i + 1));
            }
        }
        importMessageVO.setSuccessCount(successCount);
        importMessageVO.setFailList(failList);
        importMessageVO.setIllegalList(illegalList);
        importMessageVO.setMsg();
        return importMessageVO;
    }

    /**
     * 验证数据是否合法
     *
     * @param user
     * @return
     */
    public boolean validImportData(Map<String, Object> user) {
        Object userName = user.get("username");
        Object realName = user.get("real_name");
        Object sex = user.get("sex");
        Object mobile = user.get("mobile");
        Object email = user.get("email");
        Object birthday = user.get("birthday");
        String phoneExp = "/^1[345789]\\d{9}$/";
        String emailExp = "/^(\\w)+(.\\w+)*@(\\w)+((.\\w+)+)$/";
        Pattern phonePattern = Pattern.compile(phoneExp);
        Pattern emailPattern = Pattern.compile(emailExp);
        if (userName == null || userName.toString().length() < 1
                || userName.toString().length() > 10) {
            return false;
        } else if (realName == null || realName.toString().length() < 1
                || realName.toString().length() > 10) {
            return false;
        } else if (sex != null && !SexEnum.MALE.getValue().equals(sex.toString())
                && !SexEnum.FEMALE.getValue().equals(sex.toString())) {
            return false;
        } else if (mobile == null || mobile.toString().length() < 1
                || mobile.toString().length() > 11 || phonePattern.matcher(mobile.toString()).matches()) {
            return false;
        } else if (email == null || email.toString().length() < 1
                || email.toString().length() > 100 || emailPattern.matcher(email.toString()).matches()) {
            return false;
        } else if (StringUtils.tranferDate(birthday) == null) {
            return false;
        }
        return true;
    }

    @Override
    public boolean existUser(String username, Long userId) {
        LambdaQueryWrapper<User> queryWrapper = Wrappers.<User>lambdaQuery()
                .eq(User::getUsername, username);
        if (userId != null) {
            queryWrapper.ne(User::getId, userId);
        }
        return baseMapper.selectCount(queryWrapper) > 0;
    }

    /**
     * 获取当前登录用户客户端id
     *
     * @return
     */
    @Override
    public String getCurrentClientId() {
        return Oauth2Utils.getClientId();
    }

    /**
     * 获取当前登录用户的id
     *
     * @return
     */
    @Override
    public Long getCurrentUserId() {
        return Oauth2Utils.getUserId();
    }

    /**
     * 获取当前登录用户名
     *
     * @return
     */
    @Override
    public String getCurrentUsername() {
        return Oauth2Utils.getUserName();
    }

    /**
     * 获取当前登录用户公司id
     *
     * @return
     */
    @Override
    public Long getCurrentUserOrgId() {
        return getUserOrgId(getCurrentUserId());
    }

    /**
     * 获取用户所属的机构id
     *
     * @param userId 用户id
     * @return
     */
    @Override
    public Long getUserOrgId(Long userId) {
        User user = baseMapper.selectById(userId);
        if (user == null) {
            return null;
        }
        return user.getOrgId();
    }

    /**
     * 获取当前登录用户信息
     *
     * @return
     */
    @Override
    public User getCurrentUser() {
        return baseMapper.selectById(getCurrentUserId());
    }

    @Override
    public List<Role> getRoleListByUserId(Long userId) {
        return baseMapper.getRoleListByUserId(userId);
    }

    @Override
    public Integer getCurrentUserDataType() {
        return getUserDataType(getCurrentUserId());
    }

    @Override
    public Integer getUserDataType(Long userId) {
        List<Role> roles = getRoleListByUserId(userId);
        if (roles == null || roles.isEmpty()) {
            return DataPermEnum.SELF_ONLY.getValue();
        }
        final Integer dataType = roles.stream()
                .max(Comparator.comparing(Role::getDataType))
                .orElseThrow(() -> new CysBusinessException(ErrorCodeEnum.ILLEGAL, "用户userId: " + userId + "数据权限类型为空"))
                .getDataType();
        return dataType;
    }

    @Override
    public DataScope getCurrentUserDataScope() {
        return getDataScope(getCurrentUserId(), null);
    }

    /**
     * 获取用户的数据权限的公司id列表或者userId
     * 1. 仅本人数据; 2. 所在部门数据; 3. 所在部门及下属部门数据; 4. 所在公司数据; 5. 所在公司及下属公司数据
     *
     * @param userId       用户id
     * @param dataPermEnum 数据权限的类型, 不为空时按传入的数据权限类型来构建DataScope
     * @return
     */
    @Override
    public DataScope getDataScope(Long userId, DataPermEnum dataPermEnum) {
        if (dataPermEnum == null) {
            Integer dataType = getUserDataType(userId);
            // 1. 仅本人数据; 2. 所在部门数据; 3. 所在部门及下属部门数据; 4. 所在公司数据; 5. 所在公司及下属公司数据
            dataPermEnum = DataPermEnum.valueOf(dataType);
        }
        User user = getById(userId);
        if (user == null) {
            throw new CysBusinessException(ErrorCodeEnum.ILLEGAL, "userId: " + userId + "对应的用户不存在");
        }
        Long orgId = user.getOrgId();
        Long deptId = user.getDeptId();
        // 只看自己数据
        if (DataPermEnum.SELF_ONLY.equals(dataPermEnum)) {
            return new DataScope()
                    .setScopeName(dataPermEnum.getScope())
                    .setScopeIds(Collections.singletonList(userId));
        }
        // 部门
        if (DataPermEnum.DEPT_ONLY.equals(dataPermEnum)) {
            return new DataScope()
                    .setScopeName(dataPermEnum.getScope())
                    .setScopeIds(Arrays.asList(deptId));
        }
        if (DataPermEnum.DEPT_AND_CHILDREN.equals(dataPermEnum)) {
            List<Long> deptIds = deptService.getDeptAndChildIdList(deptId);
            return new DataScope()
                    .setScopeName(dataPermEnum.getScope())
                    .setScopeIds(deptIds);
        }
        // 公司/机构
        if (DataPermEnum.ORG_ONLY.equals(dataPermEnum)) {
            return new DataScope()
                    .setScopeName(dataPermEnum.getScope())
                    .setScopeIds(Arrays.asList(orgId));
        }
        if (DataPermEnum.ORG_AND_CHILDREN.equals(dataPermEnum)) {
            List<Long> orgIds = organizationService.getOrgAndChildIdList(orgId);
            return new DataScope()
                    .setScopeName(dataPermEnum.getScope())
                    .setScopeIds(orgIds);
        }
        return null;
    }

}
